package sicnu.cs.ich.common.common.concurrent;


import com.alibaba.fastjson.JSON;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.api.common.enums.ConfigEnum;

import java.util.HashMap;
import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 统计确定长度内的频率
 *
 * @author CaiKe
 * @date 2021/11/7 16:57
 */
public class FrequencyCountQueue {

    int count;

    int takeIndex;

    int[] record;

    final int[] items;

    final ReentrantLock lock;

    private final int NULL_INT = -1;

//    private final Condition notEmpty;

//    private final Condition notFull;

    public FrequencyCountQueue(int capacity, int typeSize) {
        this(capacity, typeSize, false);
    }

    public FrequencyCountQueue(int capacity, int typeSize, boolean fair) {
        if (capacity <= 0 || typeSize <= 0) {
            throw new IllegalArgumentException();
        }
        this.record = new int[typeSize + 1];
        this.lock = new ReentrantLock(fair);
        this.items = new int[capacity];
    }


    public void update(int e) throws InterruptedException {
        if (e == 0) {
            throw new IllegalArgumentException();
        }
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // add e to record
            record[e]++;
            // if full, dequeue then enqueue
            if (count == items.length) {
                dequeue();
            }
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

    private void dequeue() {
        final int[] items = this.items;
        items[takeIndex] = NULL_INT;
        if (++takeIndex == items.length) takeIndex = 0;
        count--;
//        notFull.signalAll();
    }

    private void enqueue(int e) {
        final int[] items = this.items;
        items[takeIndex] = e;
        if (++takeIndex == items.length) takeIndex = 0;
        count++;
    }

    public int[] getRecord() {
        return this.record.clone();
    }

    public void loadConfig(HashMap<ConfigEnum, String> configMap) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            Optional.ofNullable(configMap.get(ConfigEnum.ICH_HIT_TYPE)).ifPresent(value ->
                    this.record = JSON.parseArray(value).toJavaObject(int[].class));
        } finally {
            lock.unlock();
        }
    }

    public void exportConfig(HashMap<ConfigEnum, String> config) {
        boolean fullZero = true;
        for (int i : record) {
            if (i != 0) {
                fullZero = false;
                break;
            }
        }
        if (!fullZero) {
            config.put(ConfigEnum.ICH_HIT_TYPE, JSON.toJSONString(this.record));
        }

    }
}